package com.wk.common;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Aspect //切面注解
@Component //将当前类注入到Spring容器中
public class LogAspect {

    //切入点，其中execution用于使用切面的连接点。使用方法：execution(方法修饰符（可选）返回类型 方法名 参数 异常模式（可选）），可使用通配符匹配字符，*可以匹配任意字符
    @Pointcut("execution(public * com.wk.controller.UserController.getUser(..))")
    public void LogAspect(){}

    @Before("LogAspect()")  //在方法前执行
    public void doBefore(JoinPoint joinPoint)
    {
        //接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //记录请求内容
        System.out.println("-------------@Before方法执行前--------------");
        System.out.println("@Before：模拟权限检查...");
        System.out.println("URL: " +request.getRequestURI().toString());
        System.out.println("HTTP_METHOD: " + request.getMethod());
        System.out.println("IP: " + request.getRemoteAddr());
        System.out.println("CLASS_METHOD: " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        System.out.println("ARGS: " + Arrays.toString(joinPoint.getArgs()));

    }

    @After("LogAspect()")  //在方法后执行
    public void doAfter(JoinPoint joinPoint)
    {
        System.out.println("-------------@After方法执行后--------------");
        System.out.println("@After：模拟释放资源...");
        System.out.println("@After：目标方法为：" +
                joinPoint.getSignature().getDeclaringTypeName() +
                "." + joinPoint.getSignature().getName());
        System.out.println("@After：参数为：" + Arrays.toString(joinPoint.getArgs()));
        System.out.println("@After：被织入的目标对象为：" + joinPoint.getTarget());
    }

    @AfterReturning(value = "LogAspect()",returning = "retVal")  //在方法执行后返回一个结果后执行
    public void doAfterReturning(JoinPoint joinPoint,Object retVal)
    {
        System.out.println("-------------@AfterReturning方法执行完成，返回内容--------------");
        System.out.println("@AfterReturning：模拟日志记录功能...");
        System.out.println("@AfterReturning：目标方法为：" +
                joinPoint.getSignature().getDeclaringTypeName() +
                "." + joinPoint.getSignature().getName());
        System.out.println("@AfterReturning：参数为：" +
                Arrays.toString(joinPoint.getArgs()));
        System.out.println("@AfterReturning：返回值为：" + retVal);
        System.out.println("@AfterReturning：被织入的目标对象为：" + joinPoint.getTarget());
    }

    @AfterThrowing("LogAspect()")  //在方法执行过程中抛出异常时执行
    public void deAfterThrowing(JoinPoint joinPoint){
        System.out.println("deAfterThrowing");
    }

    /**------上面四个方法可以使用JoinPoint，JoinPoint包含类名、被切面的方法名，参数等信息**/


    @Around("LogAspect()")  //环绕通知，是在执行前后都使用，这个方法的参数必须为ProceedingJoinPoint，proceed()方法就是被切面的方法，
    public Object deAround(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("-------------@Around环绕--------------");
        System.out.println("@Around：执行目标方法之前...");
        Object[] args = joinPoint.getArgs();
        if (args !=null && args.length >0 && args[0].getClass() ==String.class)
        {
            //args[0] = "改变后的参数1";

        }
        //用改变后的参数执行目标方法
        Object retVal = joinPoint.proceed();  //joinPoint.proceed(args);
        System.out.println("@Around：执行目标方法之后...");
        System.out.println("@Around：被织入的目标对象为：" + joinPoint.getTarget());
        System.out.println("原返回值：" + retVal + "，这是返回结果的后缀");
        return retVal;

    }

}
